#include "libcursemania.h"

int init_curses() {
    /* initialize curses */
    initscr();
    /* character at a time output */
    cbreak();
    /* automatically suppress characters typed into tty */
    noecho();
    /* set up non blocking getch capabilities */
    nodelay(stdscr, TRUE);
    /* enable capture of special keystrokes by getch() */
    keypad(stdscr, TRUE);

    /* signal success */
    return 0;
}

/* performs game related initialization */
int init_mania() {
    /* print hello message */
    wprintw(stdscr, " LIBCURSEMANIA v0.1\n\n       developed by\n             strlst");
    wrefresh(stdscr);

    /* set initial frame */
    frame = 0;

    /* set initial key states */
    arrow_l_pressed = 0;
    arrow_d_pressed = 0;
    arrow_u_pressed = 0;
    arrow_r_pressed = 0;

    int main_size_h, main_size_w;
    /* get size of stdscr */
    getmaxyx(stdscr, main_size_h, main_size_w);
    main_h = main_size_h;
    main_w = main_size_w;

    /* draw main playfield */
    create_playfield();

    int game_pos_y, game_pos_x;
    int game_size_h, game_size_w;
    /* query size and position information for create statements */
    getbegyx(game_win, game_pos_y, game_pos_x);
    getmaxyx(game_win, game_size_h, game_size_w);
    game_y = game_pos_y;
    game_x = game_pos_x;
    game_h = game_size_h;
    game_w = game_size_w;

    /* draw stage */
    create_stage();

    /* draw receptors */
    create_receptors();

    /* draw frame display */
    create_frame_display();

    /* draw log area */
    create_log();

    return 0;
}

/* cleanup */
int destroy_mania() {
    /* destroys win instances and frees memory */
    for (int i = 0; i < 4; i++)
        delwin(receptors_win[i]);
    delwin(l_border_win);
    delwin(r_border_win);
    delwin(frame_display_win);
    delwin(log_win);
    delwin(game_win);
}

/* get user input */
void get_input(int* quit) {
    int ch;
    while ((ch = getch()) != ERR) {
        switch (ch) {
            case ARROW_LEFT:
                arrow_l_pressed = 1;
                break;
            case ARROW_DOWN:
                arrow_d_pressed = 1;
                break;
            case ARROW_UP:
                arrow_u_pressed = 1;
                break;
            case ARROW_RIGHT:
                arrow_r_pressed = 1;
                break;
            case 'q':
                *quit = 1;
                break;
        }
    }
}

/* process internal game logic */
void update_mania() {
    /* manage frames */
    frame++;
    if (frame > 60)
        frame = frame % 60;
}

/* render main playfield */
void render_mania() {
    render_stage();

    /* clear playfield before rendering */
    //werase(game_win);
    /* print fps text for debugging purposes */
    //wprintw(game_win, "frame is %i", frame);
    /* make curses call to render */
    //wrefresh(game_win);

    //render_receptors();

    //render_frame_display();
}

/* render receptor number i at pos (x0, y0) */
void render_receptor(int i, int x0, int y0) {
    wmove(receptors_win[i], y0, x0);
    //for (int i = 0; i < receptor_w; i++) {
    //    for (int j = 0; j < receptor_w; j++) {
    //        wprintw(receptors_win, "%c", ARROW_C);
    //    }
    //    wprintw(receptors_win, "%c", '\n');
    //}
    for (int i = 0; i < receptor_w; i++)
        wprintw(receptors_win[i], "%c", ARROW_C);

    wmove(receptors_win[i], y0, x0);
}

/* render all receptors */
void render_receptors() {
    /* clear playfield before rendering */
    for (int i = 0; i < 4; i++)
        werase(receptors_win[i]);

    int receptor_changed = 0;
    if (arrow_l_pressed) {
        receptor_changed = 1;
        render_receptor(0, 0, 0);
        arrow_l_pressed = 0;
    }

    if (arrow_d_pressed) {
        receptor_changed = 1;
        render_receptor(1, receptor_w, 0);
        arrow_d_pressed = 0;
    }

    if (arrow_u_pressed) {
        receptor_changed = 1;
        render_receptor(2, receptor_w * 2, 0);
        arrow_u_pressed = 0;
    }

    if (arrow_r_pressed) {
        receptor_changed = 1;
        render_receptor(3, receptor_w * 3, 0);
        arrow_r_pressed = 0;
    }

    if (!receptor_changed)
        return;

    for (int i = 0; i < 4; i++)
        wrefresh(receptors_win[i]);
}

void render_stage() {
    //wrefresh(l_border_win);
    //wrefresh(r_border_win);
}

/* render frame display */
void render_frame_display() {
    werase(frame_display_win);

    /* print fps text for debugging purposes */
    wprintw(frame_display_win, "%i", frame);

    wrefresh(frame_display_win);
}

/* create main playfield */
void create_playfield() {
    /* get quarter window boundary */
    int boundary_w = floor(main_w / 2);
    /* create a new window within stdsrc */
    game_win = newwin(main_h, boundary_w, 0, boundary_w / 2);
}

/* create receptor row below main playfield */
void create_receptors() {
    /* quasect playfield width for respective receptor width */
    /* (bisect, trisect, quasect..?) */
    receptor_w = floor(game_w / 4);

    /* rendered characters tend towards half the height of their width */
    int receptor_h = receptor_w / 2;
    /* anchor at bottom */
    int receptor_y = game_h - receptor_h;
    int receptor_x = (main_w - game_w) / 2;

    /* create receptor window just below game_win */
    /*
        receptor_w   quadratic shape, height part
        receptor_w   quadratic shape,  width part
        receptor_y   y0 directly at playfield height minus actual
                     receptor height
        receptor_x   x0 identical to playfield x0 / 4 anchored to playfield
    */
    int receptors[4] = { ARROW_LEFT, ARROW_DOWN, ARROW_UP, ARROW_RIGHT };
    for (int i = 0; i < 4; i++) {
        receptors_win[i] = newwin(receptor_w / 2, receptor_w, receptor_y, receptor_x);
        receptor_x += receptor_w;
        fill_window(receptors_win[i], receptors[i]);
    }
}

/* create stage around main playfield */
void create_stage() {
    /* query strlen for offset calc */
    int border_len_l = strlen(BORDER_L);
    int border_len_r = strlen(BORDER_R);

    /* create border windows just outside game_win */
    /*
        main_h,                total height of win
        border_len_l,          total width of win
        game_y,                initial column pos of win
        game_x - border_len_l, initial line pos of win
    */
    l_border_win = newwin(main_h, border_len_l, game_y, game_x - border_len_l);
    r_border_win = newwin(main_h, border_len_r, game_y, game_x + border_len_r + game_w);

    /* loop every line and place border string */
    for (int fh = 0; fh < main_h; fh++) {
        /* print defined border sequence */
        wprintw(l_border_win, BORDER_L);
        wprintw(r_border_win, BORDER_R);
    }

    wrefresh(l_border_win);
    wrefresh(r_border_win);
}

void create_frame_display() {
    /* create frame display in the upper right corner */
    /* for dimension parameters refer to create_stage */
    frame_display_win = newwin(1, 3, 0, main_w - 3);

    wrefresh(frame_display_win);

    fill_window(frame_display_win, 'f');
}

void create_log() {
    /* query strlen for border sizes */
    int border_len_l = strlen(BORDER_L);
    int border_len_r = strlen(BORDER_R);

    int log_h = main_h - 3;
    /* half a panel of the main window excluding the game window, minus borders */
    /* and 2 characters around each individual window */
    int log_w = (main_w - game_w - 3 * border_len_l) / 2 - 2;
    int log_y = 2;
    int log_x = main_w - log_w - 1;
    /* create log box on the right with available space */
    /* for dimension parameters refer to create_stage */
    log_win = newwin(log_h, log_w, log_y, 0);

    wprintw(log_win, " *** LOG ***\n");

    wrefresh(log_win);

    fill_window(log_win, 'l');

    log_changed = 0;
}

/* to test correct dimensions, fill a window */
void fill_window(WINDOW* win, const char filler) {
    int wh, ww;
    getmaxyx(win, wh, ww);

    werase(win);

    for (int i = 0; i < ww * wh; i++)
        wprintw(win, "%c", filler);

    wrefresh(win);
}
